#ifndef KNXENGINE_H
#define KNXENGINE_H

#include <QObject>
#include <QHostAddress>
#include <QUdpSocket>
#include <QMap>
#include <QList>
#include <QTime>
#include <QTimer>
#include "qt_knx.h"

class KNXEngine : public QObject
{
    Q_OBJECT
public:

    enum IPS_TUNNELLING_STEP {
        TUNNELLING_STANDBY = 0,
        TUNNELLING_REQ_TO_SERVER = 1,
        TUNNELLING_ACK_FROM_SERVER = 2,
        TUNNELLING_REQ_FROM_SERVER = 3,
        TUNNELLING_ACK_TO_SERVER = 4
    };

    explicit KNXEngine(QObject *parent = 0);
    ~KNXEngine();   

    void initNetWorkEnv(QString serverIp, QString localIpAddr, quint16 cntPort, quint16 dataPort, KNX_CONNECT_TYPE type = KNX_IPS);
    bool isConnectToServer();

    int busMonitor_data_len;

    quint16 server_port;
    quint16 control_port;
    quint16 data_port;

    KNX_CONNECT_TYPE connectType;
    QHostAddress ipV4Server;
    QHostAddress ipV4local;
    QHostAddress ipKnxBoardcast;
    QUdpSocket udpSend,udpRcv_cnt,udpRcv_data,udpBordcast,udpBordcastSend;
    QString self;

    bool readyWork();
    void startWork();
    void stopWork();

    void udpSendToKnx(char *data,quint32 len);
    void udpBordcastSendTo(char *data,quint32 len);

signals:
    void engineValueNotify(void *devObj,QByteArray value,void *userdata);
//    void bytes_callback(QByteArray device_addr,QByteArray value,void *userdata);
//    void onebit_callback(QByteArray device_addr,QByteArray value,void *userdata);
    void engineErrorNotify(QString msg,int errcode);
    void routingMonitorNotify(QString addr,QByteArray value);

private slots:

    void autoConnectKnx();
    void readControlSocket();
    void readDataSocket();
    void readDataBordcast();

    void connectToKnx();
    void disconnectFromKnx();

    void searchKnxServer();
    void ipsHeartBeat();

public slots:
    void setValue(QByteArray address,int type,QByteArray value);
    void getValue(QByteArray address, int type);

    bool registeObject(void *devObj,void *userdata);
    bool unRegisterObject(void *devObj,void *userdata);
    void unRegisterAll();
    void updateObjs();

private:
    void setKnxServerIp(QString ip);
    void data_analyze(_u8 *msg, int msg_len);
    void search_response(_u8 *msg,int msg_len);

    void connect_response(_u8 *msg,int msg_len);
    void disconnect_response(_u8 *msg,int msg_len);

    void startHeartBeat();
    void stopHeartBeat();

    void connect_state();
    void connect_state_response(_u8 *msg,int msg_len);

    _int32 connect_error_handle(_u8 errcode);
    _int32 message_device_data_handle(DEVICE_OBJECT *data,_u8 *value,_u8 value_len);

    //tunneling
    void tunneling_ack_from_knx(_u8 *msg,int msg_len);
    void reset_tunnelling_sc();

    void set_cid(_u8 cid);
    _u8 get_cid();

    _u8 sequence_num_add();
    _u8 get_sequence_num();
    void set_sequence_num(_u8 sc);

    bool g_tunnelling_sync_wait;

    void tunneling_sync_start();
    bool tunneling_sync_wait();
    void tunneling_sync_finish();

    _u16 onebit_tunnelling_request(_u8 channelID,_u8 writebuffer[],_u32 len, _u8 addr_array[2],_u8 value);
    _u16 bytes_tunnelling_request(_u8 channelID, _u8 writebuffer[], _u32 len, _u8 addr_array[2], _u8 bytes[], _u8 bytes_len);

    _u16 send_tunneling_ack(_u8 sc);
    _u8 * tunneling_request_from_knx(_u8 *recv_buf, _u32 len);

    //routing
    //_int32 routing_testing(_u8 addr[2],_u8 addr_type);
    _int32 routing_indication_recv_analyze(_u8 data[],_u32 data_type,_u8 *operation_type,
                                           _u8 **ret_value,_u8 *ret_len);

    _int32 bytes_routing(_u8 writebuffer[], _u32 len, _u8 addr_array[2], _u8 bytes[], _u8 bytes_len);
    _int32 onebyte_routing(_u8 writebuffer[],_u32 len,_u8 addr_array[2],_u8 value);
    _int32 onebit_routing(_u8 writebuffer[], _u32 len, _u8 addr_array[2], _u8 value);

    //read & write
    _u8 common_buffer[MAX_RECV_MSG_LEN];
    _u8 common_data_buffer[16];

    _int32 ips_read_status(_u8 addr[2]);
    _int32 ipr_read_status(_u8 addr[2]);

    _int32 ipr_send_data(_u8 addr[2],_u8 addr_type,_u8 value_type,_u8 *data,_u32 len);
    _int32 ips_send_data(_u8 addr[2],_u8 addr_type,_u8 value_type,_u8 *data,_u32 len);

    bool isConnected;
    bool currentState;
    KNX_SERVER g_knx_server;
    quint8 g_sequence_num;
    quint8 g_channel_id;

    QTimer connectTimer;

    QTime heartBeat;
    QTimer beatTimer;

    QTime tunnelTime;
    QTimer tunnellingTimer;

    QMultiMap<QByteArray, DEVICE_OBJECT *> _registersMap;
};

#endif // KNXENGINE_H
